/*
 * main.cpp
 *
 *  Created on: 18/05/2010
 *      Author: Jorge Antonio García Galicia
 */
#include <iostream>
#include <cstdlib>
#include <GL/glut.h>

#include "geometry/Vector3D.h"
#include "physics/Particle.h"
#include "physics/EulerIntegrator.h"
#include "physics/RungeKuttaIntegrator.h"
#include "graphics/Sphere.h"

#define MUNDO 100.0f   // Tope de las coordenados de el mundo
#define DT 0.1f

using namespace std;
using namespace geometry;
using namespace physics;
using namespace graphics;

void redimensiona(GLsizei w, GLsizei h);
void dibuja(void);
void inicializa(void);
void tecladoEspecial(int key, int mx, int my);
void funcionTiempo(void);
void moverEscena(void);
void teclado(unsigned char key, int mx, int my);

float tiempo;
Particle a, b, c;
Sphere izquierda(10.0), centro(10.0), derecha(10.0);

int main (int argc, char* argv[]) {

	glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
    glutInitWindowSize(400, 400);
    glutInitWindowPosition(100, 100);
    glutCreateWindow("Tres Ejemplos de caida libre");
    inicializa();
    /** Funciones de callback */
    glutSpecialFunc(tecladoEspecial);
    glutDisplayFunc(dibuja);
    glutReshapeFunc(redimensiona);
    glutKeyboardFunc(teclado);
    //glutIdleFunc(funcionTiempo);
    glutMainLoop();

    return 0;
}

void inicializa(void)
{
     glClearColor(1.0, 1.0, 1.0, 1.0);

     tiempo = 0.0f;
     Vector3D cero(0, 0, 0);

     //Inicializamos las particulas
     a.setPosition(Vector3D(-2.0 * MUNDO / 3.0, 0, 0));
     a.setVelocity(cero);
     a.setForce(cero);
     a.setMass(1.0);

     b.setPosition(Vector3D(0, 0, 0));
     b.setVelocity(cero);
     b.setForce(cero);
     b.setMass(1.0);

     c.setPosition(Vector3D(2.0 * MUNDO / 3.0, 0, 0));
     c.setVelocity(cero);
     c.setForce(cero);
     c.setMass(1.0);

     //Inicializamos los objetos graficos
     izquierda = Sphere(10.0);
     izquierda.setColor(Vector3D(1, 0, 0));
     centro = Sphere(10.0);
     centro.setColor(Vector3D(0, 1, 0));
     derecha = Sphere(10.0);
     derecha.setColor(Vector3D(0, 0, 1));
}

void redimensiona(GLsizei w, GLsizei h) {
    GLfloat aspectRatio;

    if (h == 0)
       h = 1;

    glViewport(0, 0, w, h);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    aspectRatio = (GLfloat)w / (GLfloat)h;

    if (w <= h)
       glOrtho(-MUNDO, MUNDO, -MUNDO / aspectRatio, MUNDO / aspectRatio, MUNDO, -MUNDO);
    else
       glOrtho(-MUNDO * aspectRatio, MUNDO * aspectRatio, -MUNDO, MUNDO, MUNDO, -MUNDO);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

void tecladoEspecial(int key, int mx, int my) {
	switch(key) {
		case GLUT_KEY_LEFT:
			tiempo += DT;
		break;

		case GLUT_KEY_RIGHT:
			tiempo -= DT;
		break;
	}

	glutPostRedisplay();
}

void funcionTiempo() {
	tiempo += DT;
	glutPostRedisplay();
}

void dibuja () {
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	moverEscena();
	izquierda.setCenter(a.getPosition());
	centro.setCenter(b.getPosition());
	derecha.setCenter(c.getPosition());

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();

	izquierda.draw();
	centro.draw();
	derecha.draw();

	glutSwapBuffers();

}

void moverEscena() {
	Vector3D gravity(0, -9.8, 0), p0(0, 0, 0), v0(0, 0, 0);
	EulerIntegrator e(DT);
	RungeKuttaIntegrator rk4(DT);

	//Movemos la primera como Euler
	a.emptyForce();
	a.addForce(gravity);
	e.integrate(a);

	//Movemos la segunda con la solución analitica
	b.emptyForce();
	b.addForce(gravity);
	b.setVelocity((tiempo * gravity) + v0);
	b.setPosition((((tiempo * tiempo) / 2.0) * gravity) + (tiempo * v0) + p0);

	//Movemos la tercera con el RK4
	c.emptyForce();
	rk4.integrate(c);

}

void teclado(unsigned char key, int mx, int my) {
	switch(key) {

	case 27:
		exit(0);
		break;

	default:
		break;
	}

	glutPostRedisplay();
}
